package com.ksvip.next.components.sequence.single.dao;
//package com.ksvip.components.sequence.dao;
//
//import java.beans.PropertyVetoException;
//import java.sql.SQLException;
//import java.util.List;
//import java.util.concurrent.Callable;
//import java.util.concurrent.ConcurrentHashMap;
//import java.util.concurrent.ExecutionException;
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
//import java.util.concurrent.FutureTask;
//import java.util.concurrent.TimeUnit;
//import java.util.concurrent.TimeoutException;
//import java.util.concurrent.atomic.AtomicInteger;
//
//import javax.sql.DataSource;
//
//import org.apache.commons.collections.CollectionUtils;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//
//import com.ksvip.components.sequence.exception.SequenceException;
//import com.ksvip.components.sequence.util.SeqUtil;
//
//public class GroupSequenceDao extends AbstractSingleSequenceDao {
//    private static final Logger                       log                 = LoggerFactory
//            .getLogger(GroupSequenceDao.class);
//    private List<DataSource>                          dataSources;
//    private int                                       outStep;
//    protected volatile String                         selectSql;
//    protected volatile String                         updateSql;
//    protected volatile String                         insertSql;
//    private int                                       dscount             = 1;
//
//    private ConcurrentHashMap<Integer, AtomicInteger> excludedKeyCount    = new ConcurrentHashMap<>(this.dscount);
//
//    private int                                       maxSkipCount        = 10;
//
//    private int                                       protectMilliseconds = 50;
//
//    private ExecutorService                           exec                = Executors.newFixedThreadPool(1);
//
//    public void init() throws SequenceException, SQLException, PropertyVetoException {
//        if (CollectionUtils.isEmpty(this.dataSources)) {
//            SequenceException sequenceException = new SequenceException("dbGroupKeys is Null ");
//            log.error("没有配置dbGroupKeys", sequenceException);
//            throw sequenceException;
//        }
//
//        this.dscount = this.dataSources.size();
//        this.outStep = (this.getInnerStep() * this.dscount);
//
//        this.insertSql = SeqUtil.getSeqInsertSql(this.getTableName(), this.getNameColumnName(),
//                this.getValueColumnName(), this.getGmtCreateColumnName(), this.getGmtModifiedColumnName());
//        this.selectSql = SeqUtil.getSeqSelectSql(this.getTableName(), this.getNameColumnName(),
//                this.getValueColumnName());
//        this.updateSql = SeqUtil.getSeqUpdateSql(this.getTableName(), this.getNameColumnName(),
//                this.getValueColumnName(), this.getGmtModifiedColumnName());
//    }
//
//    @Override
//    public SequenceRange nextRange(final String name) throws SequenceException {
//        if (name == null) {
//            log.error("序列名为空！");
//            throw new IllegalArgumentException("序列名称不能为空");
//        }
//
//        int[] randomIntSequence = SeqUtil.randomIntSequence(this.dscount);
//        for (int i = 0; i < this.getRetryTimes(); i++) {
//            for (int j = 0; j < this.dscount; j++) {
//                boolean readSuccess = false;
//                boolean writeSuccess = false;
//                int index = randomIntSequence[j];
//                if (this.excludedKeyCount.get(Integer.valueOf(index)) != null) {
//                    if (this.excludedKeyCount.get(Integer.valueOf(index)).incrementAndGet() > this.maxSkipCount) {
//                        this.excludedKeyCount.remove(Integer.valueOf(index));
//                        log.error(this.maxSkipCount + "次数已过，index为" + index + "的数据源后续重新尝试取序列");
//                    }
//
//                } else {
//                    final DataSource tGroupDataSource = this.dataSources.get(index);
//                    long newValue = 0L;
//                    long oldValue = 0L;
//                    try {
//                        if (this.excludedKeyCount.size() >= this.dscount - 1) {
//                            oldValue = SeqUtil.selectSeqValue(tGroupDataSource, this.selectSql, name).longValue();
//                        } else {
//                            FutureTask<Long> future = new FutureTask<Long>(new Callable<Long>() {
//                                @Override
//                                public Long call() throws Exception {
//                                    return SeqUtil.selectSeqValue(tGroupDataSource, GroupSequenceDao.this.selectSql,
//                                            name);
//                                }
//                            });
//                            try {
//                                this.exec.submit(future);
//                                oldValue = future.get(this.protectMilliseconds, TimeUnit.MILLISECONDS).longValue();
//                            } catch (InterruptedException e) {
//                                throw new SQLException("[SEQUENCE SLOW-PROTECTED MODE]:InterruptedException", e);
//                            } catch (ExecutionException e) {
//                                throw new SQLException("[SEQUENCE SLOW-PROTECTED MODE]:ExecutionException", e);
//                            } catch (TimeoutException e) {
//                                throw new SQLException("[SEQUENCE SLOW-PROTECTED MODE]:TimeoutException,当前设置超时时间为"
//                                        + this.protectMilliseconds, e);
//                            }
//                        }
//                        if (oldValue < 0L) {
//                            StringBuilder message = new StringBuilder();
//                            message.append("Sequence value cannot be less than zero, value = ").append(oldValue);
//                            message.append(", please check table ").append(this.getTableName());
//                            log.info(message.toString());
//
//                            continue;
//                        }
//
//                        if (oldValue > Long.MAX_VALUE) {
//                            StringBuilder message = new StringBuilder();
//                            message.append("Sequence value overflow, value = ").append(oldValue);
//                            message.append(", please check table ").append(this.getTableName());
//                            log.info(message.toString());
//                            continue;
//                        }
//
//                        newValue = oldValue + this.outStep;
//                        if (!this.check(index, newValue)) {
//                            if (this.isAdjust()) {
//                                newValue = newValue - newValue % this.outStep + this.outStep
//                                        + index * this.getInnerStep();
//                            } else {
//                                SequenceException sequenceException = new SequenceException(this.dataSources.get(index)
//                                        + ":" + name + "的值得错误，覆盖到其他范围段了！请修改数据库，或者开启adjust开关！");
//
//                                log.error(this.dataSources.get(index) + ":" + name
//                                        + "的值得错误，覆盖到其他范围段了！请修改数据库，或者开启adjust开关！", sequenceException);
//
//                                throw sequenceException;
//                            }
//                        }
//                    } catch (SQLException e) {
//                        log.error("取范围过程中--查询出错！" + this.dataSources.get(index) + ":" + name, e);
//
//                        if (this.excludedKeyCount.size() < this.dscount - 1) {
//                            this.excludedKeyCount.put(Integer.valueOf(index), new AtomicInteger(0));
//                            log.error("暂时踢除index为" + index + "的数据源，" + this.maxSkipCount + "次后重新尝试");
//                        }
//
//                        continue;
//                    }
//                    readSuccess = true;
//                    try {
//                        int affectedRows = SeqUtil.updateSeqValue(tGroupDataSource, this.updateSql, newValue, name,
//                                oldValue);
//                        if (affectedRows == 0) {
//                            continue;
//                        }
//                    } catch (Exception e) {
//                        log.error("取范围过程中--更新出错！" + this.dataSources.get(index) + ":" + name, e);
//                        continue;
//                    }
//                    writeSuccess = true;
//                    if ((readSuccess) && (writeSuccess)) {
//                        return new SequenceRange(newValue + 1L, newValue + this.getInnerStep());
//                    }
//                }
//            }
//            if (i == this.getRetryTimes() - 2) {
//                this.excludedKeyCount.clear();
//            }
//        }
//        log.error("所有数据源都不可用！且重试" + this.getRetryTimes() + "次后，仍然失败!");
//        throw new SequenceException("All dataSource faild to get value!");
//    }
//
//    @Override
//    public void adjust(String name) throws SequenceException, SQLException {
//        for (int i = 0; i < this.dataSources.size(); i++) {
//            DataSource tGroupDataSource = this.dataSources.get(i);
//            if (tGroupDataSource == null) {
//                log.debug("datasource is null:" + i);
//            }
//            try {
//                Long value = SeqUtil.selectSeqValue(tGroupDataSource, this.selectSql, name);
//                if (value == null) {
//                    if (this.isAdjust()) {
//                        this.adjustInsert(tGroupDataSource, i, name);
//                    } else {
//                        log.error("数据库中未配置该sequence！请往数据库中插入sequence记录，或者启动adjust开关");
//                        throw new SequenceException("数据库中未配置该sequence！请往数据库中插入sequence记录，或者启动adjust开关");
//                    }
//
//                } else if (!this.check(i, value.longValue())) {
//                    if (this.isAdjust()) {
//                        this.adjustUpdate(tGroupDataSource, i, value.longValue(), name);
//                    } else {
//                        log.error("数据库中配置的初值出错！请调整你的数据库，或者启动adjust开关");
//                        throw new SequenceException("数据库中配置的初值出错！请调整你的数据库，或者启动adjust开关");
//                    }
//                }
//            } catch (SQLException e) {
//                log.error("初值校验和自适应过程中出错.", e);
//                throw e;
//            }
//        }
//    }
//
//    private void adjustUpdate(DataSource tGroupDataSource, int index, long value, String name)
//            throws SequenceException, SQLException {
//        long newValue = value - value % this.outStep + this.outStep + index * this.getInnerStep();
//        try {
//            int affectedRows = SeqUtil.updateSeqValue(tGroupDataSource, this.updateSql, newValue, name, value);
//            if (affectedRows == 0) {
//                throw new SequenceException("faild to auto adjust init value at  " + name + " update affectedRow =0");
//            }
//
//            log.info(this.dataSources.get(index) + "更新初值成功!" + "sequence Name：" + name + "更新过程：" + value + "-->"
//                    + newValue);
//        } catch (Exception e) {
//            log.error("由于SQLException,更新初值自适应失败！dbGroupIndex:" + this.dataSources.get(index) + "，sequence Name：" + name
//                    + "更新过程：" + value + "-->" + newValue, e);
//
//            throw new SequenceException("由于SQLException,更新初值自适应失败！dbGroupIndex:" + this.dataSources.get(index)
//                    + "，sequence Name：" + name + "更新过程：" + value + "-->" + newValue, e);
//        }
//    }
//
//    private void adjustInsert(DataSource tGroupDataSource, int index, String name)
//            throws SequenceException, SQLException {
//        long newValue = index * this.getInnerStep();
//        try {
//            int affectedRows = SeqUtil.insertSeq(tGroupDataSource, this.insertSql, name, newValue);
//            if (affectedRows == 0) {
//                throw new SequenceException("faild to auto adjust init value at  " + name + " update affectedRow =0");
//            }
//            log.info(this.dataSources.get(index) + "   name:" + name + "插入初值:" + name + "value:" + newValue);
//        } catch (Exception e) {
//            log.error("由于SQLException,插入初值自适应失败！dbGroupIndex:" + this.dataSources.get(index) + "，sequence Name：" + name
//                    + "   value:" + newValue, e);
//            throw new SequenceException("由于SQLException,插入初值自适应失败！dbGroupIndex:" + this.dataSources.get(index)
//                    + "，sequence Name：" + name + "   value:" + newValue, e);
//        }
//    }
//
//    private boolean check(int index, long value) {
//        return value % this.outStep == index * this.getInnerStep();
//    }
//
//    public List<DataSource> getDataSources() {
//        return this.dataSources;
//    }
//
//    public void setDataSources(List<DataSource> dataSources) {
//        this.dataSources = dataSources;
//    }
//}
